package com.android.systemui.ios;

import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.graphics.drawable.Drawable;
import android.os.Bundle;
import android.os.Handler;
import android.os.IBinder;
import android.os.Looper;
import android.os.Message;
import android.os.RemoteException;
import android.util.DisplayMetrics;
import android.util.Log;
import android.view.Gravity;
import android.view.LayoutInflater;
import android.view.MotionEvent;
import android.view.WindowManager;

import com.android.systemui.ios.notice.AllNoticesLayout;
import com.android.systemui.ios.notice.NoticeData;
import com.android.systemui.ios.views.ShadeBarWindowView;

import org.json.JSONException;
import org.json.JSONObject;

public class ShadeBarController {

    private final boolean DEBUG = true;
    private final String TAG = "wss";

    private ShadeBarWindowView mMainView;
    private AllNoticesLayout mNoticeLayout;
    private WindowManager mWindowManager;
    private PackageManager mPackageManager;
    private WindowManager.LayoutParams mParams;

    private final Context mContext;
    private IGuardService mService;
    private IStatusBarCallback mDateTimeView;
    private IStatusBarCallback mStatusBarShortcut;
    private boolean isHideFromOccluded = false;

    public ShadeBarController(Context context) {
        mContext = context;
        mPackageManager = context.getPackageManager();
        mWindowManager = context.getSystemService(WindowManager.class);
    }

    public void create() {
        DisplayMetrics metrics = new DisplayMetrics();
        mWindowManager.getDefaultDisplay().getRealMetrics(metrics);
        Constants.screenWidth = metrics.widthPixels;
        Constants.screenHeight = metrics.heightPixels;
        Constants.screenDensity = metrics.density;

        mMainView = (ShadeBarWindowView) LayoutInflater.from(mContext).inflate(R.layout.shade_bar_main_layout, null);
        mNoticeLayout = mMainView.findViewById(R.id.all_notices_layout);
        mDateTimeView = mMainView.getDateTimeView();
        mStatusBarShortcut = mMainView.getShortcutIcons();
    }

    public void setParams(WindowManager.LayoutParams params) {
        mParams = params;
    }

    public WindowManager getWindowManager() {
        return mWindowManager;
    }

    public ShadeBarController setService(IGuardService service) {
        mService = service;
        mMainView.setActionEventCallback(mService, mEventCallback);
        mNoticeLayout.setActionEventCallback(mService, mEventCallback);
        return this;
    }

    public ShadeBarController addCallback(ISystemGuardChangedCallback guard, IStatusBarWindowChangedCallback window) {
        mService.registerStatusChangedCallback(guard);
        mService.registerWindowChangedCallback(window);
        return this;
    }

    public ShadeBarController removeCallback(ISystemGuardChangedCallback guard, IStatusBarWindowChangedCallback window) {
        mService.unregisterStatusChangedCallback(guard);
        mService.unregisterWindowChangedCallback(window);
        return this;
    }

    public ShadeBarWindowView getWindowView() {
        return mMainView;
    }

    public ISystemGuardChangedCallback getGuardCallback() {
        return mGuardCallback;
    }

    public IStatusBarWindowChangedCallback getStatusBarWindowCallback() {
        return mStatusBarWindowCallback;
    }

    private final int MSG_DISTURB = 1;
    private final int MSG_BRIGHTNESS = 2;
    private final int MSG_AIRPLANE = 3;
    private final int MSG_HOTSPOT = 4;
    private final int MSG_TORCH = 5;
    private final int MSG_ROTATION = 6;
    private final int MSG_AUDIO = 7;
    private final int MSG_GPS = 8;
    private final int MSG_RECORDING = 10;
    private final int MSG_BT = 11;
    private final int MSG_WIFI = 12;
    private final int MSG_SIM = 13;
    private final int MSG_BATTERY = 15;
    private final int MSG_NOTIFICATION = 16;

    private final int MSG_UPDATE_WINDOW_HEIGHT = 100;
    private final int MSG_UPDATE_WINDOW_Y = 101;
    private final int MSG_UPDATE_WINDOW_EXPAND = 102;
    private final int MSG_UPDATE_WINDOW_COLLAPSE = 103;
    private final int MSG_UPDATE_WINDOW_RESET = 104;

    private final Handler mHandler = new Handler(Looper.myLooper()) {

        @Override
        public void handleMessage(Message msg) {
            Bundle bundle;
            switch (msg.what) {
                case MSG_DISTURB:
                    mDateTimeView.onDisturbChanged(msg.arg1 == 1);
                    mStatusBarShortcut.onDisturbChanged(msg.arg1 == 1);
                    break;
                case MSG_BRIGHTNESS:
                    mDateTimeView.onBrightnessChanged(msg.arg1 == 1, msg.arg2);
                    mStatusBarShortcut.onBrightnessChanged(msg.arg1 == 1, msg.arg2);
                    break;
                case MSG_AIRPLANE:
                    mDateTimeView.onAirplaneModeChanged(msg.arg1 == 1);
                    mStatusBarShortcut.onAirplaneModeChanged(msg.arg1 == 1);
                    break;
                case MSG_HOTSPOT:
                    mDateTimeView.onHotspotStateChanged(msg.arg1 == 1, msg.arg2);
                    mStatusBarShortcut.onHotspotStateChanged(msg.arg1 == 1, msg.arg2);
                    break;
                case MSG_TORCH:
                    mDateTimeView.onTorchChanged(msg.arg1 == 1, msg.arg2 == 1);
                    mStatusBarShortcut.onTorchChanged(msg.arg1 == 1, msg.arg2 == 1);
                    break;
                case MSG_ROTATION:
                    mDateTimeView.onScreenAutoRotationChanged(msg.arg1 == 1);
                    mStatusBarShortcut.onScreenAutoRotationChanged(msg.arg1 == 1);
                    break;
                case MSG_GPS:
                    mDateTimeView.onGpsChanged(msg.arg1 == 1, msg.arg2 == 1);
                    mStatusBarShortcut.onGpsChanged(msg.arg1 == 1, msg.arg2 == 1);
                    break;
                case MSG_RECORDING:
                    mDateTimeView.onScreenRecordingChanged(msg.arg1, msg.arg2);
                    mStatusBarShortcut.onScreenRecordingChanged(msg.arg1, msg.arg2);
                    break;
                case MSG_BT:
                    bundle = msg.getData();
                    boolean open3 = bundle.getBoolean("open");
                    boolean connected = bundle.getBoolean("connected");
                    String name = bundle.getString("name");
                    mDateTimeView.onBluetoothChanged(open3, connected, name);
                    mStatusBarShortcut.onBluetoothChanged(open3, connected, name);
                    break;
                case MSG_WIFI:
                    bundle = msg.getData();
                    boolean open4 = bundle.getBoolean("open");
                    boolean connected4 = bundle.getBoolean("connected");
                    int signal = bundle.getInt("signal");
                    int network4 = bundle.getInt("network");
                    int rssi = bundle.getInt("rssi");
                    String name4 = bundle.getString("name");
                    mDateTimeView.onWifiChanged(open4, connected4, signal, network4, name4);
                    mStatusBarShortcut.onWifiChanged(open4, connected4, signal, network4, name4);
                    break;
                case MSG_SIM:
                    bundle = msg.getData();
                    int count = bundle.getInt("count");
                    int subId = bundle.getInt("subId");
                    boolean insert5 = bundle.getBoolean("insert");
                    int signal5 = bundle.getInt("signal");
                    int network = bundle.getInt("network");
                    int dataType = bundle.getInt("dataType");
                    String name5 = bundle.getString("name");
                    mDateTimeView.onSimStateChanged(count, subId, insert5, signal5, network, dataType, name5);
                    mStatusBarShortcut.onSimStateChanged(count, subId, insert5, signal5, network, dataType, name5);
                    break;
                case MSG_AUDIO:
                    bundle = msg.getData();
                    boolean silent = bundle.getBoolean("silent");
                    boolean vibrate = bundle.getBoolean("vibrate");
                    int stream = bundle.getInt("stream");
                    int volume = bundle.getInt("volume");
                    mDateTimeView.onAudioStateChanged(stream, volume, silent, vibrate);
                    mStatusBarShortcut.onAudioStateChanged(stream, volume, silent, vibrate);
                    break;
                case MSG_BATTERY:
                    bundle = msg.getData();
                    int level = bundle.getInt("level");
                    boolean pluggedIn = bundle.getBoolean("pluggedIn");
                    boolean charging = bundle.getBoolean("charging");
                    boolean powerSave = bundle.getBoolean("powerSave");
                    mDateTimeView.onBatteryChanged(level, pluggedIn, charging, powerSave);
                    mStatusBarShortcut.onBatteryChanged(level, pluggedIn, charging, powerSave);
                    break;
                case MSG_NOTIFICATION:
                    String msgJson = (String) msg.obj;
                    NoticeData noticeData = new NoticeData();
                    try {
                        JSONObject jsonObject = new JSONObject(msgJson);
                        noticeData.setTitle(jsonObject.optString("title"));
                        noticeData.setSummary(jsonObject.optString("message"));
                        noticeData.setWhen(jsonObject.optLong("when"));
                        noticeData.setPkgName(jsonObject.optString("pkg"));
                        noticeData.setKey(jsonObject.optString("key"));
                        noticeData.setFlags(jsonObject.optInt("flags", 0));
                        try {
                            Drawable drawable = mPackageManager.getApplicationIcon(noticeData.getPkgName());
                            noticeData.setIcon(drawable);
                        } catch (PackageManager.NameNotFoundException e) {
                            e.printStackTrace();
                        }
                    } catch (JSONException e) {
                        e.printStackTrace();
                    }
                    switch (msg.arg2) {
                        case 0: // Remove
                            mNoticeLayout.removeNotice(noticeData);
                            break;
                        case 1: // Add
                            mNoticeLayout.addNotice(noticeData);
                            break;
                        case 2: // Update
                            mNoticeLayout.updateNotice(noticeData);
                            break;
                    }
                    break;
                case MSG_UPDATE_WINDOW_HEIGHT:
                    if (mParams != null) {
                        mParams.alpha = 1.0f;
                        mParams.gravity = Gravity.TOP;
                        mParams.height = WindowManager.LayoutParams.MATCH_PARENT;
                        mWindowManager.updateViewLayout(mMainView, mParams);
                    }
                    if (msg.arg1 == 1) { // Shortcut
                        mMainView.startFromTopShortcut();
                    } else {
                        mMainView.updateLocation(-Constants.screenHeight + msg.arg2);
                    }
                    if (mService != null) {
                        mService.setNavVisible(1);
                    }
                    break;
                case MSG_UPDATE_WINDOW_Y:
                    mMainView.updateLocation(msg.arg1);
                    break;
                case MSG_UPDATE_WINDOW_EXPAND:
                    if (msg.arg2 == 1) { // Expand
                        if (msg.arg1 == 1) { // Shortcut
                            mMainView.showShortcut();
                        }
                        mMainView.smoothExpand();
                    } else {
                        if (msg.arg1 == 1) { // Shortcut
                            mMainView.hideShortcut();
                        } else {
                            mMainView.smoothCollapse();
                        }
                    }
                    break;
                case MSG_UPDATE_WINDOW_COLLAPSE:
                    mEventCallback.onCollapse();
                    break;
                case MSG_UPDATE_WINDOW_RESET:
                    mEventCallback.onResetKeyguard();
                    break;
            }
        }
    };

    private final IActionEventCallback mEventCallback = new IActionEventCallback() {

        @Override
        public void onOpenNotification() {
            if (mMainView.checkPassword()) {
                mMainView.smoothCollapse();
            }
        }

        @Override
        public void onAnimationCollapse() {
            mMainView.smoothCollapse();
        }

        @Override
        public void onShortcutClose() {
            mMainView.hideShortcut();
        }

        @Override
        public void onEntryWallpaperManager() {
            mMainView.showWallpaperSelect();
        }

        @Override
        public void onCollapse() {
            mMainView.setFacePreviewEnable(false);
            if (mParams != null) {
                if (Constants.KEYGUARD_ENABLE && mService.isLocked()) {
                    mParams.alpha = 0.0f;
                    mParams.gravity = Gravity.BOTTOM;
                    mParams.height = (int) (10 * Constants.screenDensity);
                } else {
                    mParams.alpha = 0.0f;
                    mParams.gravity = Gravity.TOP;
                    mParams.height = 1;
                }
                mWindowManager.updateViewLayout(mMainView, mParams);
            }
            KeyguardActivity.hide(mContext);
            Constants.isExpanded = false;
            if (mService != null) {
                mService.setNavVisible(0);
            }
        }

        @Override
        public void onResetKeyguard() {
            if (Constants.KEYGUARD_ENABLE) {
                if (mParams != null) {
                    mParams.alpha = 1.0f;
                    mParams.gravity = Gravity.TOP;
                    mParams.height = WindowManager.LayoutParams.MATCH_PARENT;
                    mWindowManager.updateViewLayout(mMainView, mParams);
                }
                KeyguardActivity.show(mContext);
                Constants.isExpanded = true;
                mMainView.updateLocation(0);
                if (mService != null) {
                    mMainView.setShowLockIcon(mService.isLocked());
                }
            }
        }

        @Override
        public void onOpenCamera() {
            try {
                Intent intent = new Intent("android.media.action.STILL_IMAGE_CAMERA");
                intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
                mContext.startActivity(intent);
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    };

    private final ISystemGuardChangedCallback mGuardCallback = new ISystemGuardChangedCallback() {

        @Override
        public IBinder asBinder() {
            return null;
        }

        @Override
        public void onDisturbChanged(boolean open) throws RemoteException {
            if (DEBUG) Log.d(TAG, "onDisturbChanged, open=" + open);
            Message msg = mHandler.obtainMessage();
            msg.what = MSG_DISTURB;
            msg.arg1 = open ? 1 : 0;
            mHandler.sendMessage(msg);
        }

        @Override
        public void onBrightnessChanged(boolean auto, int brightness) throws RemoteException {
            if (DEBUG)
                Log.d(TAG, "onBrightnessChanged. auto=" + auto + ", brightness=" + brightness);
            Message msg = mHandler.obtainMessage();
            msg.what = MSG_BRIGHTNESS;
            msg.arg1 = auto ? 1 : 0;
            msg.arg2 = brightness;
            mHandler.sendMessage(msg);
        }

        @Override
        public void onAirplaneModeChanged(boolean open) throws RemoteException {
            if (DEBUG) Log.d(TAG, "onAirplaneModeChanged, open=" + open);
            Message msg = mHandler.obtainMessage();
            msg.what = MSG_AIRPLANE;
            msg.arg1 = open ? 1 : 0;
            mHandler.sendMessage(msg);
        }

        @Override
        public void onHotspotStateChanged(boolean enabled, int numDevices) throws RemoteException {
            if (DEBUG)
                Log.d(TAG, "onHotspotStateChanged. enabled=" + enabled + ", numDevices=" + numDevices);
            Message msg = mHandler.obtainMessage();
            msg.what = MSG_HOTSPOT;
            msg.arg1 = enabled ? 1 : 0;
            msg.arg2 = numDevices;
            mHandler.sendMessage(msg);
        }

        @Override
        public void onGpsChanged(boolean open, boolean active) throws RemoteException {
            if (DEBUG)
                Log.d(TAG, "onGpsChanged. open=" + open);
            Message msg = mHandler.obtainMessage();
            msg.what = MSG_GPS;
            msg.arg1 = open ? 1 : 0;
            msg.arg2 = active ? 1 : 0;
            mHandler.sendMessage(msg);
        }

        @Override
        public void onBluetoothChanged(boolean open, boolean connected, String name) throws RemoteException {
            if (DEBUG)
                Log.d(TAG, "onBluetoothChanged. open=" + open + ", connected=" + connected + ", name=" + name);
            Bundle bundle = new Bundle();
            bundle.putBoolean("open", open);
            bundle.putBoolean("connected", connected);
            bundle.putString("name", name);
            Message msg = mHandler.obtainMessage();
            msg.what = MSG_BT;
            msg.setData(bundle);
            mHandler.sendMessage(msg);
        }

        @Override
        public void onWifiChanged(boolean open, boolean connected, int signal, int network, String name) throws RemoteException {
            if (DEBUG)
                Log.d(TAG, "onWifiChanged. open=" + open + ", connected=" + connected + ", signal=" + signal + ", network=" + network + ", name=" + name);
            Bundle bundle = new Bundle();
            bundle.putBoolean("open", open);
            bundle.putBoolean("connected", connected);
            bundle.putInt("signal", signal);
            bundle.putInt("network", network);
            bundle.putString("name", name);
            Message msg = mHandler.obtainMessage();
            msg.what = MSG_WIFI;
            msg.setData(bundle);
            mHandler.sendMessage(msg);
        }

        @Override
        public void onSimStateChanged(int count, int subId, boolean insert, int signal, int network, int dataType, String name) throws RemoteException {
            if (DEBUG)
                Log.d(TAG, "onSimStateChanged. count=" + count + ", subId=" + subId + ", insert=" + insert + ", signal=" + signal + ", name=" + name);
            Bundle bundle = new Bundle();
            bundle.putInt("count", count);
            bundle.putInt("subId", subId);
            bundle.putBoolean("insert", insert);
            bundle.putInt("signal", signal);
            bundle.putInt("network", network);
            bundle.putInt("dataType", dataType);
            bundle.putString("name", name);
            Message msg = mHandler.obtainMessage();
            msg.what = MSG_SIM;
            msg.setData(bundle);
            mHandler.sendMessage(msg);
        }

        @Override
        public void onTorchChanged(boolean available, boolean open) throws RemoteException {
            if (DEBUG)
                Log.d(TAG, "onTorchChanged. available=" + available + ", open=" + open);
            Message msg = mHandler.obtainMessage();
            msg.what = MSG_TORCH;
            msg.arg1 = available ? 1 : 0;
            msg.arg2 = open ? 1 : 0;
            mHandler.sendMessage(msg);
        }

        @Override
        public void onAudioStateChanged(int stream, int volume, boolean silent, boolean vibrate) throws RemoteException {
            if (DEBUG)
                Log.d(TAG, "onAudioStateChanged. stream=" + stream + ", volume=" + volume + ", silent=" + silent + ", vibrate=" + vibrate);
            Bundle bundle = new Bundle();
            bundle.putInt("stream", stream);
            bundle.putInt("volume", volume);
            bundle.putBoolean("silent", silent);
            bundle.putBoolean("vibrate", vibrate);
            Message msg = mHandler.obtainMessage();
            msg.what = MSG_AUDIO;
            msg.setData(bundle);
            mHandler.sendMessage(msg);
        }

        @Override
        public void onScreenAutoRotationChanged(boolean open) throws RemoteException {
            if (DEBUG) Log.d(TAG, "onScreenAutoRotationChanged. open=" + open);
            Message msg = mHandler.obtainMessage();
            msg.what = MSG_ROTATION;
            msg.arg1 = open ? 1 : 0;
            mHandler.sendMessage(msg);
        }

        @Override
        public void onScreenRecordingChanged(int state, int time) throws RemoteException {
            if (DEBUG)
                Log.d(TAG, "onScreenRecordingChanged. state=" + state + ", time=" + time);
            Message msg = mHandler.obtainMessage();
            msg.what = MSG_RECORDING;
            msg.arg1 = state;
            msg.arg2 = time;
            mHandler.sendMessage(msg);
        }

        @Override
        public void onBatteryChanged(int level, boolean pluggedIn, boolean charging, boolean powerSave) throws RemoteException {
            if (DEBUG)
                Log.d(TAG, "onBatteryChanged. level=" + level + ", pluggedIn=" + pluggedIn + ", charging=" + charging + ", powerSave=" + powerSave);
            Bundle bundle = new Bundle();
            bundle.putInt("level", level);
            bundle.putBoolean("pluggedIn", pluggedIn);
            bundle.putBoolean("charging", charging);
            bundle.putBoolean("powerSave", powerSave);
            Message msg = mHandler.obtainMessage();
            msg.what = MSG_BATTERY;
            msg.arg1 = 0;
            msg.setData(bundle);
            mHandler.sendMessage(msg);
        }

        @Override
        public void onNotificationChanged(int action, String msgJson) throws RemoteException {
            mHandler.obtainMessage(MSG_NOTIFICATION, 0, action, msgJson).sendToTarget();
        }
    };

    private final IStatusBarWindowChangedCallback mStatusBarWindowCallback = new IStatusBarWindowChangedCallback() {

        private float mDownY;
        private float mDeltaY;
        private int mShowShortcut = 0;
        private boolean isInShowKeyguard = false;

        @Override
        public IBinder asBinder() {
            return null;
        }

        @Override
        public void onWindowHeightChanged(int height, boolean keyguard, boolean occluded) throws RemoteException {
            if (Constants.KEYGUARD_ENABLE) {
                if (occluded) {
                    if (Constants.isExpanded) {
                        isHideFromOccluded = true;
                        mHandler.obtainMessage(MSG_UPDATE_WINDOW_COLLAPSE).sendToTarget();
                    }
                } else {
                    if (isHideFromOccluded) {
                        mHandler.obtainMessage(MSG_UPDATE_WINDOW_RESET).sendToTarget();
                    }
                    isHideFromOccluded = false;
                }
            } else {
                isInShowKeyguard = keyguard;
            }
        }

        @Override
        public void onDragWindowMoved(int action, float x, float y, float velocityX, float velocityY) throws RemoteException {
            if (!Constants.isExpanded && !isInShowKeyguard) {
                switch (action) {
                    case MotionEvent.ACTION_DOWN:
                        mDownY = y;
                        mShowShortcut = x > Constants.screenWidth * 3.0f / 4.0f ? 1 : 0;
                        mHandler.obtainMessage(MSG_UPDATE_WINDOW_HEIGHT, mShowShortcut, (int) y).sendToTarget();
                        break;
                    case MotionEvent.ACTION_MOVE:
                        mDeltaY = y;// - mDownY;
                        mHandler.obtainMessage(MSG_UPDATE_WINDOW_Y, (int) (mDeltaY - Constants.screenHeight), 0).sendToTarget();
                        break;
                    case MotionEvent.ACTION_UP:
                    case MotionEvent.ACTION_CANCEL:
                        if (mDeltaY > Constants.pageTurningSize || velocityY > Constants.pageTurningVelocity) {
                            mHandler.obtainMessage(MSG_UPDATE_WINDOW_EXPAND, mShowShortcut, 1).sendToTarget();
                        } else {
                            mHandler.obtainMessage(MSG_UPDATE_WINDOW_EXPAND, mShowShortcut, 0).sendToTarget();
                        }
                        break;
                }
            }
        }

        @Override
        public void onDirectionChanged(int rotation, int width, int height) throws RemoteException {
            Log.e("wss", "onDirectionChanged, rotation = " + rotation + ", width=" + width + ", height=" + height);
        }

        @Override
        public void onThemeChanged(boolean dark) throws RemoteException {
            Log.e("wss", "onThemeChanged, dark = " + dark);
        }

        @Override
        public void onVerifyFaceIdResult(int state, int progress) throws RemoteException {
            Log.e("wss", "onVerifyFaceIdResult, state = " + state + ", progress=" + progress);
        }
    };
}
